package com.gitee.wsl.func

fun interface InvokeCall<in T, out R>{

    operator fun invoke(t:T):R

    /**
     * Returns a composed function that first applies the `before`
     * function to its input, and then applies this function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of input to the `before` function, and to the
     * composed function
     * @param before the function to apply before this function is applied
     * @return a composed function that first applies the `before`
     * function and then applies this function
     * @throws NullPointerException if before is null
     *
     * @see .andThen
    </V> */
    fun <V> andThen(after: InvokeCall< R,  V>): InvokeCall<T, V> {
        return InvokeCall { t: T -> after(invoke(t)) }
    }

   /* fun <V> andThen(after: InvokeCall<R, V>): InvokeCall<T, V> {
        return InvokeCall { t: T -> after.invoke(invoke(t)) }
    }*/

    /**
     * Returns a composed function that first applies this function to
     * its input, and then applies the `after` function to the result.
     * If evaluation of either function throws an exception, it is relayed to
     * the caller of the composed function.
     *
     * @param <V> the type of output of the `after` function, and of the
     * composed function
     * @param after the function to apply after this function is applied
     * @return a composed function that first applies this function and then
     * applies the `after` function
     * @throws NullPointerException if after is null
     *
     * @see .compose
    </V> */
    fun <V> compose(before: InvokeCall<V, T>): InvokeCall<V, R> {
        return InvokeCall { v: V -> invoke(before.invoke(v)) }
    }

}

operator fun <T> InvokeCall<T, Boolean>.plus(other: InvokeCall<T, Boolean>): InvokeCall<T, Boolean> {
    val validator=this
    return InvokeCall{ validator(it) && other(it) }
}

infix fun <T> InvokeCall<T, Boolean>.or(other: InvokeCall<T, Boolean>): InvokeCall<T, Boolean> {
    val validator=this
    return InvokeCall{ validator(it) || other(it) }
}

operator fun <T> InvokeCall<T, Boolean>.unaryMinus(): InvokeCall<T, Boolean> {
    val validator = this
    return InvokeCall{ !validator(it) }
}

operator fun <T> Function<T, Unit>?.plus(other: Function<T, Unit>?): Function<T, Unit> {
    return Function<T, Unit>{it->
        this@plus?.invoke(it)
        other?.invoke(it)
    }
}